package com.fowo.api.costAccounting.service.impl;

import com.alibaba.fastjson.JSON;
import com.fowo.api.costAccounting.entity.CostConfig;
import com.fowo.api.costAccounting.mapper.CommonCostingMapper;
import com.fowo.api.costAccounting.mapper.MonthlyCostReportMapper;
import com.fowo.api.costAccounting.model.bd.BdAccperiodmonthVo;
import com.fowo.api.costAccounting.model.cost.CostConfigProductVo;
import com.fowo.api.costAccounting.model.monthly.MonthlyCostReportItemVo;
import com.fowo.api.costAccounting.model.monthly.MonthlyVo;
import com.fowo.api.costAccounting.model.stock.StockInMonthlyVo;
import com.fowo.api.costAccounting.service.CostAccountingBusinessTableService;
import com.fowo.api.costAccounting.service.CostConfigProductService;
import com.fowo.api.costAccounting.service.CostConfigService;
import com.fowo.api.costAccounting.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import tech.tablesaw.api.Row;
import tech.tablesaw.api.Table;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class CostAccountingBusinessTableServiceImpl implements CostAccountingBusinessTableService {
    @Resource
    protected CostConfigService costConfigService;
    @Resource
    protected CostConfigProductService costConfigProductService;
    @Resource
    private MonthlyCostReportMapper monthlyCostReportMapper;
    @Resource
    private CommonCostingMapper commonCostingMapper;

    @Override
    public void updateMonthlyCostReport(String serialNumber) throws Exception {
        CostConfig costConfig = costConfigService.getSerialNumber(serialNumber);
        List<CostConfigProductVo> costConfigProductList= costConfigProductService.getByCostConfigId(costConfig.getId());
        if(costConfigProductList.size()==0){
            throw new Exception("成本子表配置查出没有符合得数据");
        }
        List<BdAccperiodmonthVo> bdAccperiodmonthVoList = commonCostingMapper.getByStatus();
        if (bdAccperiodmonthVoList.size() != 1) {
            throw new Exception("会计月份查出多条或没有符合得数据");
        }
        if (bdAccperiodmonthVoList.get(0).getBeginDate() == null || bdAccperiodmonthVoList.get(0).getEndDate() == null) {
            throw new Exception("会计月份开始时间结束日期未设置");
        }
        this.threadTable(costConfig, bdAccperiodmonthVoList.get(0),costConfigProductList);
    }

    /**
     *
     * @param costConfig
     * @param bdAccperiodmonthVo
     * @param costConfigProductList
     * @throws Exception
     */
    public void threadTable(CostConfig costConfig, BdAccperiodmonthVo bdAccperiodmonthVo, List<CostConfigProductVo> costConfigProductList) throws Exception {
        //sql server 不支持ifnull  数据库默认0
        //List<MonthlyCostReportItemVo> monthlyCostReportItemVos = monthlyCostReportMapper.getByPeriodId(costConfig.getType().toString(), bdAccperiodmonthVo.getId());
        List<MonthlyCostReportItemVo> monthlyCostReportItemVos = monthlyCostReportMapper.getByModelPeriodId(costConfig.getType().toString(), bdAccperiodmonthVo.getId());
        if(monthlyCostReportItemVos.size()==0){
            throw new Exception("成本月报表暂无数据");
        }
        String sql = this.selectsql(costConfig, bdAccperiodmonthVo);
        //入库数据
        List<StockInMonthlyVo> stockInMonthlyVoList = commonCostingMapper.selectStockInSql(sql);
        System.out.println("处理转table--" + new Date());
        String monthlyCostReportItemString = JSON.toJSONString(monthlyCostReportItemVos);
        Table table = Table.read().string(monthlyCostReportItemString, "json");
        Table result=table;
        if(stockInMonthlyVoList.size()!=0){
            String stockInMonthlyVoListString = JSON.toJSONString(stockInMonthlyVoList);
            Table table1 = Table.read().string(stockInMonthlyVoListString, "json");
            result = this.result(costConfig,table,table1);
        }
        System.out.println("处理转tablejieshu--"+new Date());
        List<String> updateSqlList=new ArrayList<>();
        Date start=new Date();
        result.forEach(t->{
            BigDecimal sumAmount=new BigDecimal(0);
            Integer sumCount=0;
            BigDecimal amount=t.getObject("amount")==null?new BigDecimal(0): new BigDecimal(t.getObject("amount").toString());
            Integer qty=t.getObject("qty")==null?0:Integer.parseInt(t.getObject("qty").toString());
            BigDecimal beginAmount=t.getObject("beginAmount")==null?new BigDecimal(0): new BigDecimal(t.getObject("beginAmount").toString());
            Integer beginQty=t.getObject("beginQty")==null?0:Integer.parseInt(t.getObject("beginQty").toString());
            //如果期初金额 0 直接直接入库金额÷入库数量
            if(beginAmount.compareTo(BigDecimal.ZERO)==0){
                sumAmount= amount;
                sumCount=  qty;
            }else {
                sumAmount= amount.add(beginAmount);
                sumCount=  qty+beginQty;
            }
            // 更新出库单  销售出库单 根据过滤得条件 筛选

            if(sumCount==0){
               return;
            }
             // /计算 当期加权平均价
              BigDecimal weightedAverage=sumAmount.divide( BigDecimal.valueOf(sumCount),2,BigDecimal.ROUND_HALF_UP);
             List<String> updatesql=this.updateSql(costConfig,t,costConfigProductList,bdAccperiodmonthVo,weightedAverage);
            if(updatesql.size()>0){
                updateSqlList.addAll(updatesql);
            }
        });

        int listSize = updateSqlList.size();
        int fetchSize = 1000; //900条执行一IC  in orcale最大查询1000
        for (int i = 0; i < updateSqlList.size(); i += fetchSize) {
            try {
                if (i + fetchSize > listSize) {        //作用为toIndex最后没有100条数据则剩余几条newList中就装几条
                    fetchSize = listSize - i;
                }
                List<String> list = updateSqlList.subList(i, i + fetchSize);
                commonCostingMapper.updateSqlList(list);
            } catch (Exception e) {
                log.info("处理失败 ", e);
            }
        }
    }

    private Table result(CostConfig costConfig,Table table,Table table1) throws Exception{
        switch (costConfig.getType()) {
            case 1:
                String [] s={"itemId","orgId"};
                return  table.joinOn(s).fullOuter(table1,true,false, s);
            case 2:
                String [] s1={"itemId","orgId","stockId"};
                return  table.joinOn(s1).fullOuter(table1,true,false, s1);
            case 3:
                String [] s2={"itemId","orgId","shopId"};
                return  table.joinOn(s2).fullOuter(table1,true,false, s2);
            default:
                throw new Exception("对应模式不符合");
        }
    }
    private String selectsql(CostConfig costConfig,BdAccperiodmonthVo bdAccperiodmonthVo) throws Exception {
        String sql=String.format(costConfig.getSelectSql(), DateUtils.getTimesBeginStr(bdAccperiodmonthVo.getBeginDate()),DateUtils.getTimesEndStr(bdAccperiodmonthVo.getEndDate()));
        return sql;
    }
    private List<String> updateSql(CostConfig costConfig, Row row, List<CostConfigProductVo> costConfigProductList, BdAccperiodmonthVo bdAccperiodmonthVo,  BigDecimal weightedAverage)  {
          List <String> sqlList =new ArrayList<>();
        for (CostConfigProductVo costConfigProductVo : costConfigProductList) {
            String sql = "";
            //根据维度(1 - 组织+物料; 2 - 组织+仓库+物料; 3 - 组织+店铺+物料; )
            switch (costConfig.getType()) {
                case 1:
                    sql=String.format(costConfigProductVo.getUpdateSql(),weightedAverage, DateUtils.getTimesBeginStr( bdAccperiodmonthVo.getBeginDate()),DateUtils.getTimesEndStr(bdAccperiodmonthVo.getEndDate()),row.getObject("orgId"),row.getObject("itemId"));
                    sqlList.add(sql);
                    break;
                case 2:
                    sql=String.format(costConfigProductVo.getUpdateSql(),weightedAverage, DateUtils.getTimesBeginStr( bdAccperiodmonthVo.getBeginDate()),DateUtils.getTimesEndStr(bdAccperiodmonthVo.getEndDate()),row.getObject("orgId"),row.getObject("stockId"),row.getObject("itemId"));
                    sqlList.add(sql);
                    break;
                case 3:
                    sql=String.format(costConfigProductVo.getUpdateSql(),weightedAverage,DateUtils.getTimesBeginStr( bdAccperiodmonthVo.getBeginDate()),DateUtils.getTimesEndStr(bdAccperiodmonthVo.getEndDate()),row.getObject("orgId"),row.getObject("shopId"),row.getObject("itemId"));
                    sqlList.add(sql);
                    break;
                default:
                    return  null;
            }
        }
        return sqlList;
    }
}
